package cloudresource

import (
	"encoding/json"
	"fmt"
	"github.com/pkg/errors"
	"io/ioutil"
	"net/http"
	errs "scase.io/application-auto-scaling-service/pkg/api/errors"
	"scase.io/application-auto-scaling-service/pkg/api/model/cci"
	"scase.io/application-auto-scaling-service/pkg/api/response"
	"scase.io/application-auto-scaling-service/pkg/common"
	"scase.io/application-auto-scaling-service/pkg/db"
	"scase.io/application-auto-scaling-service/pkg/setting"
	"scase.io/application-auto-scaling-service/pkg/utils/core"
	"scase.io/application-auto-scaling-service/pkg/utils/logger"
	"strings"
)

type PodResourceController struct {
	AK string
	SK string
}

func GetPodController(oriProjectId string) (*PodResourceController, error) {
	agencyInfo, err := db.GetAgencyInfo(oriProjectId)
	if err != nil {
		return nil, err
	}
	newPodResourceController := PodResourceController{
		AK: agencyInfo.AccessKey,
		SK: agencyInfo.SecretAccessKey,
	}
	return &newPodResourceController, nil
}

// 创建pod，通过状态码判断是否下达成功，使用查询pod接口更新创建状态
func (c *PodResourceController) CreatePod(createPodRequest interface{}, namespace string) error {
	signer := core.Signer{
		Key:    c.AK,
		Secret: c.SK,
	}
	method := "POST"
	cciEndpoint := setting.CloudClientPodEndpoint
	url := fmt.Sprintf(cciEndpoint+common.CreatePodURL, namespace)
	payload, err := convertStructToReader(createPodRequest)
	if err != nil {
		return err
	}
	client := &http.Client{}
	req, err := http.NewRequest(method, url, payload)
	if err != nil {
		return err
	}
	req.Header.Add(common.XStage, common.Release)
	req.Header.Add(response.HttpContentType, "application/json")
	_ = signer.Sign(req)
	res, err := client.Do(req)
	if err != nil {
		return err
	}
	defer res.Body.Close()
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return err
	}
	if res.StatusCode != common.CCICreatedCode {
		errResp := cci.ErrorResponseForCCI{}
		err = json.Unmarshal(body, &errResp)
		if err != nil {
			return err
		}
		return fmt.Errorf(errResp.Message)
	}
	return nil
}

func (c *PodResourceController) QueryNamespaceExist(namespace string) error {
	signer := core.Signer{
		Key:    c.AK,
		Secret: c.SK,
	}
	method := "GET"
	cciEndpoint := setting.CloudClientPodEndpoint
	url := cciEndpoint + common.NamespaceURL + "/" + namespace
	client := &http.Client{}
	payload := strings.NewReader(``)
	req, err := http.NewRequest(method, url, payload)
	if err != nil {
		return err
	}
	req.Header.Add(common.XStage, common.Release)
	req.Header.Add(response.HttpContentType, "application/json")
	_ = signer.Sign(req)
	res, err := client.Do(req)
	if err != nil {
		return err
	}
	defer res.Body.Close()
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return err
	}
	if res.StatusCode != common.CCIQueryCode {
		errResp := cci.ErrorResponseForCCI{}
		err = json.Unmarshal(body, &errResp)
		if err != nil {
			return err
		}
		return fmt.Errorf(errResp.Message)
	}
	queryResp := &cci.QueryPodResp{}
	if err := json.Unmarshal(body, queryResp); err != nil {
		return err
	}
	return nil
}

func (c *PodResourceController) QueryPod(namespace, podName string) (*cci.QueryPodResp, error) {
	signer := core.Signer{
		Key:    c.AK,
		Secret: c.SK,
	}
	method := "GET"
	cciEndpoint := setting.CloudClientPodEndpoint
	url := fmt.Sprintf(cciEndpoint+common.QueryPodURL, namespace, podName)
	client := &http.Client{}
	payload := strings.NewReader(``)
	req, err := http.NewRequest(method, url, payload)
	if err != nil {
		return nil, err
	}
	req.Header.Add(common.XStage, common.Release)
	req.Header.Add(response.HttpContentType, "application/json")
	_ = signer.Sign(req)
	res, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, err
	}
	if res.StatusCode == common.CCINotFoundCode {
		return nil, errors.Wrap(common.ErrPodNotFound, fmt.Sprintf("namespace %s pod %s not found", namespace, podName))
	}
	if res.StatusCode != common.CCIQueryCode {
		errResp := cci.ErrorResponseForCCI{}
		err = json.Unmarshal(body, &errResp)
		if err != nil {
			return nil, err
		}
		return nil, fmt.Errorf(errResp.Message)
	}
	queryResp := &cci.QueryPodResp{}
	if err := json.Unmarshal(body, queryResp); err != nil {
		return nil, err
	}
	return queryResp, nil
}

func (c *PodResourceController) DeleteNamespace(namespace string, groupId string, log *logger.FMLogger) error {
	signer := core.Signer{
		Key:    c.AK,
		Secret: c.SK,
	}
	method := "DELETE"
	cciEndpoint := setting.CloudClientPodEndpoint
	url := cciEndpoint + fmt.Sprintf(common.DeleteNamespaceURL, namespace)
	payload := strings.NewReader(`{}`)
	client := &http.Client{}
	req, err := http.NewRequest(method, url, payload)
	if err != nil {
		log.Error("create [deleting] namespace [%s] request error:%+v", groupId, err)
		return err
	}
	req.Header.Add(common.XStage, common.Release)
	req.Header.Add(response.HttpContentType, "application/json")
	if err = signer.Sign(req); err != nil {
		log.Error("set [deleting] namespace [%s] authorization header error:%+v", groupId, err)
		return err
	}
	res, err := client.Do(req)
	if err != nil {
		log.Error("delete namespace [%s] in cloud error:%+v", groupId, err)
		return err
	}
	defer res.Body.Close()
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		log.Error("read [deleting] namespace [%s] responsebody error:%+v", groupId, err)
		return err
	}
	if res.StatusCode != common.CCIQueryCode && res.StatusCode != common.CCINotFoundCode {
		errResp := cci.ErrorResponseForCCI{}
		err = json.Unmarshal(body, &errResp)
		if err != nil {
			log.Error("unmarshal [deleting] namespace [%s] requestbody error:%+v", err)
			return err
		}
		return errs.NewErrorRespWithMessage(errs.DeleteNamespaceNetworkError, errResp.Message)
	}
	return nil
}

// 成功删除返回200，重复删除时返回404
func (c *PodResourceController) DeletePod(namespace, podName string) error {
	signer := core.Signer{
		Key:    c.AK,
		Secret: c.SK,
	}
	method := "DELETE"
	cciEndpoint := setting.CloudClientPodEndpoint
	url := fmt.Sprintf(cciEndpoint+common.QueryPodURL, namespace, podName)
	client := &http.Client{}
	payload := strings.NewReader(``)
	req, err := http.NewRequest(method, url, payload)
	if err != nil {
		return err
	}
	req.Header.Add(common.XStage, common.Release)
	req.Header.Add(response.HttpContentType, "application/json")
	_ = signer.Sign(req)
	res, err := client.Do(req)
	if err != nil {
		return err
	}
	defer res.Body.Close()
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return err
	}
	if res.StatusCode != common.CCIQueryCode && res.StatusCode != common.CCINotFoundCode {
		errResp := cci.ErrorResponseForCCI{}
		err = json.Unmarshal(body, &errResp)
		if err != nil {
			return err
		}
		return fmt.Errorf(errResp.Message)
	}
	return nil
}

func (c *PodResourceController) CountNamespacePods(namespace string) (int, error) {
	signer := core.Signer{
		Key:    c.AK,
		Secret: c.SK,
	}
	method := "GET"
	cciEndpoint := setting.CloudClientPodEndpoint
	url := fmt.Sprintf(cciEndpoint+common.CreatePodURL, namespace)
	payload := strings.NewReader(`{}`)
	client := &http.Client{}
	req, err := http.NewRequest(method, url, payload)
	if err != nil {
		return 0, err
	}
	req.Header.Add(common.XStage, common.Release)
	req.Header.Add(response.HttpContentType, "application/json")
	if err = signer.Sign(req); err != nil {
	}
	res, err := client.Do(req)
	if err != nil {
		return 0, err
	}
	defer res.Body.Close()
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return 0, err
	}
	if res.StatusCode != common.CCIQueryCode {
		errResp := cci.ErrorResponseForCCI{}
		err = json.Unmarshal(body, &errResp)
		if err != nil {
			return 0, err
		}
		return 0, fmt.Errorf(errResp.Message)
	}
	itemResp := cci.QueryNamespaceResp{}
	if err := json.Unmarshal(body, &itemResp); err != nil {
		return 0, err
	}
	return len(itemResp.Items), nil
}

func convertStructToReader(data interface{}) (*strings.Reader, error) {
	jsonStr, err := json.Marshal(data)
	if err != nil {
		return nil, err
	}
	reader := strings.NewReader(string(jsonStr))
	return reader, nil
}
